﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;

namespace YBOT_Field_Control
{
    public class Game

    {
        #region Board and Relay Variables
            public int maxTowerNum = 10;        //Total # of towers in game
            public string xbPort = "COM4";      //Defaul XBee Com Port
        #endregion

        #region Game and Scoring Variables

            OneWire g1w;                        //One Wire constructor
            XBee gXB;                           //Xbee Constructor
            Field_Control gFC;                  //Field Control Constructor
            LogWriter gLW = new LogWriter();    //Log Writer Constructor
            Time gTime = new Time();            //Time Constructor

            public string time =                //Time of day stamp
                  DateTime.Now.Hour.ToString() + "_" 
                + DateTime.Now.Minute.ToString() + "_" 
                + DateTime.Now.Second.ToString();


            public TeamVariables red = new TeamVariables("red");            //New team 
            public TeamVariables green = new TeamVariables("green");        //New team
            public TeamVariables computer = new TeamVariables("computer");  //New team 

            public int autoModeTime = 20;   //Autonomous Mode time in secs
            public int midModeTime = 75;    //Mid Mode time + automode time
            public int matchNumber = 0;     //Current match number


            //Game flags
            public bool gameDone = false;       //True when game has finished
            public bool STOP = true;           //True when game has been stopped
            public bool autoMode = false;       //True when game is in autonomous mode
            public bool midMode = false;        //True when game is in middle game mode
            public bool endMode = false;        //True when game is in end of game mode
            public bool practiceMode = false;   //True when game is in practice mode

            public int penality = 5;            //Poinst per penality

        //------------------------------------------------------------------------------------------------\\
        //Current year's game variables
        //------------------------------------------------------------------------------------------------\\

            public bool firstHit = false;               //First hit flag
            public int autoMax = 6;                     //Max number of scores in autonomous
            private Random randomNum = new Random();    //Random Number
            private int autoButtonTime = 5;             //Number of seconds a team has to press a button in autonomous mode
            Time autoTime = new Time();                 //Time Constructor
            private int totalGlobes = 12;               //Total number of globes;
            private bool cycleComplete = true;          //cycle flag
            public int globePoints = 2;                 //Points per Globe

        #endregion 

        #region Constructors

            public Game()
            {
                this.g1w = new OneWire();
                this.gXB = new XBee();
                this.gFC = new Field_Control();
            }

            public Game(OneWire _g1w)
            {
                this.g1w = _g1w;
            }

            public Game(XBee _gXB)
            {
                this.gXB = _gXB;
            }

            public Game(Field_Control _gFC)
            {
                this.gFC = _gFC;
            }

            public Game(OneWire _g1w, XBee _gXB)
            {
                this.g1w = _g1w;
                this.gXB = _gXB;
            }

            public Game(OneWire _g1w, XBee _gXB, Field_Control _gFC)
            {
                this.g1w = _g1w;
                this.gXB = _gXB;
                this.gFC = _gFC;
            }

        #endregion

        //Initiate game class
        public void begin()
        {
            //red.setTowers();                    //Define Red team towers
            //green.setTowers();                  //Define Green Team towers
            red.reset();                        //Reset Red variables
            green.reset();                      //Reset Green variables
            computer.reset();
            midMode = false;                    //Reset midGame flag
            endMode = false;                    //Reset endGame flag
            cycleComplete = false;               //Reset Speed round cycle flag
            firstHit = false;
            computer.midScore = 35;             //Computer's starting Score;
        }

        /// <summary>
        /// Start a new game
        /// </summary>
        public void GameStartUp()
        {
            begin();
            gFC.StartUp();
            STOP = false;
            gameDone = false;
            practiceMode = false;
            autoMode = true;

            GameLog("Game Started");
            autoMax = 6;

            //Reset Ball Release
            //gFC.fcXB.Send("reset");

            //Ring Bell
            gFC.RingBell();

            //Turn on All Field Lights
            gFC.AllLights(true);

            //Turn off All Field Lights
            gFC.AllLights(false);

            //Turn on Beacons
            gFC.Light(1, false, false, true, true);
            gFC.Light(5, false, false, true, true);
            gFC.Light(6, false, false, true, true);
            gFC.Light(10, false, false, true, true);

            //Turn on Robot Transmiters
            gFC.RobotTransmitters(true, true);
            GameLog("Transmitters On");

            GameLog("Game Start");

        }

        /// <summary>
        /// Start a new game
        /// </summary>
        public void GameStartUp(bool _autoMode, bool _practiceMode)
        {
            begin();
            gFC.StartUp();
            STOP = false;
            gameDone = false;
            autoMode = _autoMode;

            practiceMode = _practiceMode;
            GameLog("Game Started");
            autoMax = 6;

            //Reset Ball Release
            gFC.fcXB.Send("reset");

            //Ring Bell
            gFC.RingBell();

            //Turn on All Field Lights
            gFC.AllLights(true);

            //Turn off All Field Lights
            gFC.AllLights(false);

            //Turn on Beacons
            gFC.Light(1, false, false, true, true);
            gFC.Light(5, false, false, true, true);
            gFC.Light(6, false, false, true, true);
            gFC.Light(10, false, false, true, true);
            
            GameLog("Transmitters On");

            //If practice mode
            if (practiceMode && _autoMode)
            {
                //Turn on Robot Transmiters
                gFC.RobotTransmitters(_autoMode, true);
            }
            else if (practiceMode)
            {
                //Turn on Robot Transmiters
                gFC.RobotTransmitters(false, true);
            }
            else
            {

            }

            GameLog("Game Start");
        }

        /// <summary>
        /// End a Game
        /// </summary>
        public void GameShutDown()
        {
            //Turn off Transmitters
            gFC.RobotTransmitters(false, false);

            //Sound buzzer
            gFC.SoundBuzzer();

            GameLog("Towers Off");
            GameLog("Game End");
        }
        
        /// <summary>
        /// Main Game control :  enters and exits game modes
        /// </summary>
        public void MainGame()
        {

            //Do loop until the game is over or stopped
            while (!STOP && !gameDone)          
            {
                //Place game mode code here
                if (!practiceMode)
                {
                    if (autoMode && !midMode && !endMode) AutoMode();
                    
                    else if (autoMode && midMode && !endMode)               
                    {
                        gFC.RobotTransmitters(3, false, true);              
                        gFC.RingBell();                                
                        autoMode = false;                                     
                        GameLog("AutoMode Over");
                        GameLog("Transmitters ON");
                        gFC.AllLights(false);
                        red.activeTeam = false;
                        green.activeTeam = false;
                        cycleComplete = true;
                    }

                    else if (!autoMode && midMode && !endMode) MidMode();

                    else if (!autoMode && midMode && endMode)
                    {
                        gFC.AllLights(true);
                        gFC.RingBell();                                     
                        midMode = false;                                     
                        GameLog("MidMode Over");
                        gFC.AllLights(false);
                        cornerLights();
                    }
                    else if (!autoMode && !midMode && endMode) EndMode();
                }
                else
                {
                    //Place Practice Mode code here
                }

                Application.DoEvents();         //Do window's stuff
                return;                         //Return to control program
            }
        }

        public void AutoMode()
        {
            byte _redState = gFC.ReadState(3);      //Check state of red's towers

            if (!cycleComplete)                     //If this is the first time thru the loop
            {
                Thread.Sleep(50);                   //Sleep thread for 1/20th of a second to make it fair
                cycleComplete = true;               //Stop this the next time thru
            }

            byte _greenState = gFC.ReadState(8);    //Check state of green's towers

            if (!firstHit)                          //If no one has pressed a button
            {              
                if (!gFC.PinRead(3, gFC.redLight)) gFC.Light(3, gFC.redLight, true);         //If red's light isn't on turn it on
                if (!gFC.PinRead(8, gFC.greenLight)) gFC.Light(8, gFC.greenLight, true);     //If green's light isn't on turn it on

                if (gFC.PinRead(3, gFC.button1))            //If red's button is pressed
                {
                    red.bonus = red.bonus + 1;              //Score bonus point
                    red.autoScore = red.autoScore + 1;      //Add one to autoScore
                    red.activeTeam = true;                  //Make red the active team
                    gFC.Light(3, gFC.redLight, false);      //Turn off light
                    gFC.Light(8, gFC.greenLight, false);    //Turn off light
                    firstHit = true;                        //A button has been pressed
                    GameLog("Red: Bonus"+"||"+"Red: Active Team" +"||" + red.autoScore.ToString());
                    
                    autoTime.elapsedTime.Restart();         //Start button timer

                    red.score = red.score + 1;

                }
                if (gFC.PinRead(8, gFC.button1))            //If green's button is pressed
                {
                    green.bonus = green.bonus + 1;          //Score bonus point
                    green.autoScore = green.autoScore + 1;  //Add on to autoScore
                    green.activeTeam = true;                //Make green the active team
                    gFC.Light(3, gFC.redLight, false);      //Turn off light
                    gFC.Light(8, gFC.greenLight, false);    //Turn off light
                    firstHit = true;                        //A button has been pressed
                    GameLog("Green: Bonus"+"||"+"Green: Active Team" + "||" + green.autoScore.ToString());

                    autoTime.elapsedTime.Restart();         //Start button timer

                    green.score = green.score + 1;
                }
                
                ballRelease();
            }

            else
            {
                if (red.activeTeam && green.activeTeam)     //If red and green are both active teams
                {
                    int coinflip = randomNum.Next(1, 3);    //Flip a coin

                    if (coinflip == 1)                      //If coin = 1
                    {
                        red.activeTeam = true;              //Red is active team
                        green.activeTeam = false;           //Green is not
                        GameLog("Red: Active Team");
                    }
                    else                                    //Else coin = 2
                    {           
                        red.activeTeam = false;             //Red is not active team
                        green.activeTeam = true;            //Green is active team
                        GameLog("Green: Active Team");
                    }
                }

                if (autoTime.Timer(autoButtonTime))         //If time is up
                {
                    if (red.activeTeam)
                    {
                        gFC.Light(8, gFC.greenLight, false);     //Turn off light
                        green.activeTeam = true;
                        red.activeTeam = false;
                        GameLog("Green: Active Team");
                    }
                    else
                    {
                        gFC.Light(3, gFC.redLight, false);   //Turn off light
                        red.activeTeam = true;
                        green.activeTeam = false;
                        GameLog("Red: Active Team");
                    }

                    autoTime.elapsedTime.Restart();          //Start button timer
                }

                if (!red.activeTeam)    //If red isn't active and globe count is less than max
                {
                    //If red's light isn't on and the button isn't pressed turn it on
                    if (!gFC.PinRead(3, gFC.redLight) && !gFC.PinRead(3, gFC.button1))
                        gFC.Light(3, gFC.redLight, true);    

                    else if (gFC.PinRead(3, gFC.redLight) && gFC.PinRead(3, gFC.button1))        //If red's button is pressed
                    {
                        red.autoScore = red.autoScore + 1;      //Add one to autoScore
                        red.activeTeam = true;                  //Make red the active team
                        green.activeTeam = false;               //Green team is not the active team
                        gFC.Light(3, gFC.redLight, false);      //Turn off light
                        ballRelease();                          //Release ball
                        GameLog("Red: Globe = " + red.autoScore.ToString() + "||" + "Red: Active Team");
                        autoTime.elapsedTime.Restart();         //Start button timer
                    }
                }

                if (!green.activeTeam)    //If green isn't active and globe count is less than max
                {
                    //If green's light isn't on and the button isn't pressed turn it on
                    if (!gFC.PinRead(8, gFC.greenLight) && !gFC.PinRead(8, gFC.button1))
                        gFC.Light(8, gFC.greenLight, true);      

                    else if (gFC.PinRead(8, gFC.greenLight) && gFC.PinRead(8, gFC.button1))           //If green's button is pressed
                    {
                        green.autoScore = green.autoScore + 1;      //Add one to autoScore
                        green.activeTeam = true;                    //Make green the active team
                        red.activeTeam = false;                     //Green team is not the active team
                        gFC.Light(8, gFC.greenLight, false);        //Turn off light
                        ballRelease();                              //Release ball
                        GameLog("Green: Globe = "+ green.autoScore.ToString() + "\r\n" + "Green: Active Team");
                        autoTime.elapsedTime.Restart();              //Start button timer

                    }
                }

            }

            computer.globeCount = totalGlobes - (red.globeCount + green.globeCount);        //Track computers globes

            //if (red.globeCount == autoMax && green.globeCount == autoMax) midMode = true; //If all the globes have been released

        }

        public void MidMode()
        {
            bool _redCorrect = false;                                                   //Set red's flag false
            bool _greenCorrect = false;                                                 //Set green's flage false


            if (cycleComplete)                                                          //If cycle is complete
            {
                gFC.AllLights(true);
                chooseTowers();                                                         //Get random towers
                gFC.AllLights(false);

                //Turn on red light and random light
                gFC.Light(red.randomTower, gFC.redLight, true);
                gFC.Light(red.randomTower, red.randomLight, true);

                //Turn on green light and random light
                gFC.Light(green.randomTower, gFC.greenLight, true);
                gFC.Light(green.randomTower, green.randomLight, true);

                Thread.Sleep(1000);                                                     //Wait 1 sec

                gFC.AllLights(false);


                //Turn off red light and random light
                gFC.Light(red.randomTower, gFC.redLight, false);
                gFC.Light(red.randomTower, red.randomLight, false);

                //Turn off green light and random light
                gFC.Light(green.randomTower, gFC.greenLight, false);
                gFC.Light(green.randomTower, green.randomLight, false);


                cycleComplete = false;                                                  //Start new cycle
            }

            else
            {
                gFC.ReadState(red.randomTower);                                         //Read red's tower status
                gFC.ReadState(green.randomTower);                                       //Read green's tower status

                if (gFC.PinRead(red.randomTower, red.randomButton) && !red.activeTeam)             //If tower equals expected state
                {
                    _redCorrect = true;                                                 //Red is correct
                    red.activeTeam = true;                                              //Red team is active 
                    gFC.Light(red.randomTower, gFC.redLight, true);                    //Turn off red light
                }

                if (gFC.PinRead(green.randomTower, green.randomButton) && !green.activeTeam)         //If tower equals expected state
                {
                    _greenCorrect = true;                                               //Green is correct
                    green.activeTeam = true;                                            //Green team is active
                    gFC.Light(green.randomTower, gFC.greenLight, true);                //Turn off green light
                }

                if(_redCorrect && _greenCorrect)                                        //If both teams have pressed there button
                {
                    red.midScore = red.midScore + 3;                                    //Score 3 points for red
                    green.midScore = green.midScore + 3;                                //Score 3 points for green
                    computer.midScore = computer.midScore - 6;                          //Subtract 3 points from computer
                    GameLog("Red Score = " + red.midScore.ToString());
                    GameLog("Green Score = " + red.midScore.ToString());
                }
                else if (_redCorrect  && !_greenCorrect)                                //If red's button is pressed but not green's
                {
                    if(green.activeTeam)                                                //If green was first
                    {
                        red.midScore = red.midScore + 2;                                //Score 2 points for red
                        computer.midScore = computer.midScore - 2;                      //Subtract 2 points for green
                        GameLog("Red Score = " + red.midScore.ToString());
                    }
                    else                                                                //Else red is the first team
                    {
                        red.midScore = red.midScore + 3;                                //Score 3 points for red
                        computer.midScore = computer.midScore - 3;                      //Subtract 3 points from computer
                        GameLog("Red Score = " + red.midScore.ToString());
                    }

                }
                else if (_greenCorrect && !_redCorrect)
                {
                    if(red.activeTeam)                                                  //If red was first
                    {
                        green.midScore = green.midScore + 2;                            //Score 2 points for green
                        computer.midScore = computer.midScore - 2;                      //Subtract 2 points for green
                        GameLog("Green Score = " + red.midScore.ToString());
                    }
                    else                                                                //Else green is the first team
                    {
                        green.midScore = green.midScore + 3;                            //Score 3 points for green
                        computer.midScore = computer.midScore - 3;                      //Subtract 3 points from computer
                        GameLog("Green Score = " + red.midScore.ToString());
                    }
                }

                if(red.activeTeam && green.activeTeam)                                  //If red and green have both pressed their buttons
                {
                    cycleComplete = true;                                               //Cycle is complete
                    red.activeTeam = false;                                             //Red team is not active
                    green.activeTeam = false;                                           //Green team is not active
                    GameLog("Cycle Complete: Computer Score = " + computer.midScore.ToString());
                }


                //Update score
                red.score = red.midScore + red.bonus;
                green.score = green.midScore + green.bonus;
                computer.score = computer.midScore;

                //Check is middle mode is complete
                if (computer.midScore < 1) endMode = true;
                if (computer.midScore < 0) computer.score = 0;
            }

        }

        public void EndMode()
        {
            //Place Main Game Code here
        }


        /// <summary>
        /// Writes text to log file
        /// </summary>
        /// <param name="text">Text as string</param>
        public void GameLog(string text)
        {
            string file = "\\Match " +   matchNumber.ToString() + " - Log";               
            string folder = "Matches\\" + "Match " + matchNumber.ToString();

            gLW.WriteLog(text, file, folder);
        }

        //------------------------------------------------------------------------------------------------\\
        //Current year's game methods
        //------------------------------------------------------------------------------------------------\\

        private void ballRelease()
        {
            int[] _tower = { 9, 10, 1, 2, 4, 5, 6, 7};

            //Turn on all field lights
            for (int i = 0; i < _tower.Length; i++)
            {
                if (red.activeTeam) gFC.Light(_tower[i], gFC.redLight, true);
                if (green.activeTeam) gFC.Light(_tower[i], gFC.greenLight, true);
            }
   
            if (red.activeTeam && red.globeCount < autoMax)             //If red team is active and globes are less than max
            {
                gFC.fcXB.Send("red,");
                red.globeCount++;                                       //Increament red's globe count
            }
            else if (green.activeTeam && green.globeCount < autoMax)    //If green team is active and globes are less than max
            {
                gFC.fcXB.Send("green,");
                green.globeCount++;                                     //Increament green's globe count
            }

            Thread.Sleep(600);

            //Turn off all field lights
            for (int i = 0; i < _tower.Length; i++)
            {
                if (red.activeTeam) gFC.Light(_tower[i], gFC.redLight, false);
                if (green.activeTeam) gFC.Light(_tower[i], gFC.greenLight, false);
            }
        }

        public void ballRelease(string _color)
        {
            int[] _tower = { 9, 10, 1, 2, 4, 5, 6, 7 };

            //Turn on all field lights
            for (int i = 0; i < _tower.Length; i++)
            {
                if (_color == "red") gFC.Light(_tower[i], gFC.redLight, true);
                if (_color == "green") gFC.Light(_tower[i], gFC.greenLight, true);
            }

            if (_color == "red" && red.globeCount < autoMax)             //If red team is active and globes are less than max
            {
                gFC.fcXB.Send("red,");
                red.globeCount++;                                       //Increament red's globe count
            }
            else if (_color == "green" && green.globeCount < autoMax)    //If green team is active and globes are less than max
            {
                gFC.fcXB.Send("green,");
                green.globeCount++;                                     //Increament green's globe count
            }

            Thread.Sleep(500);

            //Turn off all field lights
            for (int i = 0; i < _tower.Length; i++)
            {
                if (_color == "red") gFC.Light(_tower[i], gFC.redLight, false);
                if (_color == "green") gFC.Light(_tower[i], gFC.greenLight, false);
            }
        }

        private void chooseTowers()
        {
            int[] _redTowers = { 1, 3, 5, 6, 8, 10 };       //Array for possible red towers
            int[] _greenTowers= { 6, 8, 10, 1, 3, 5 };      //Array for possible green towers

            int t = randomNum.Next(0, 6);                   //Pick a random number

            red.randomTower = _redTowers[t];                //Set random red tower
            green.randomTower = _greenTowers[t];            //Set random green tower

            if (red.randomTower == 8 || red.randomTower == 3)
            {
                red.randomLight = gFC.redLight;
                red.randomButton = gFC.button1;
            }
            else
            {
                int l = randomNum.Next(1, 3);                   //Pick a random number
                if (l == 1)
                {
                    red.randomLight = gFC.blueLight;
                    red.randomButton = gFC.button1;
                }
                else 
                {
                    red.randomLight = gFC.yellowLight;
                    red.randomButton = gFC.button2;
                }
            }

            if (green.randomTower == 8 || green.randomTower == 3)
            {
                green.randomLight = gFC.greenLight;
                green.randomButton = gFC.button1;
            }
            else
            {
                int l = randomNum.Next(1, 3);                   //Pick a random number
                if (l == 1)
                {
                    green.randomLight = gFC.blueLight;
                    green.randomButton = gFC.button1;
                }
                else
                {
                    green.randomLight = gFC.yellowLight;
                    green.randomButton = gFC.button2;
                }
            }

        }

        public void cornerLights()
        {
            int coinFlip = randomNum.Next(1, 3);

            if (coinFlip == 1)
            {
                gFC.Light(2, gFC.redLight, true);
                gFC.Light(4, gFC.greenLight, true);
                gFC.Light(7, gFC.redLight, true);
                gFC.Light(9, gFC.greenLight, true);
            }
            else
            {
                gFC.Light(2, gFC.greenLight, true);
                gFC.Light(4, gFC.redLight, true);
                gFC.Light(7, gFC.greenLight, true);
                gFC.Light(9, gFC.redLight, true);
            }

        }

    }
}
